package io.kimmking.rpcfx.register.center.redis;

import com.alibaba.fastjson.JSON;
import io.kimmking.rpcfx.api.Router;
import io.kimmking.rpcfx.proxy.CustomInterceptor;
import io.kimmking.rpcfx.register.center.api.Discovery;
import io.kimmking.rpcfx.register.center.api.DiscoveryInfo;
import io.kimmking.rpcfx.register.center.api.ProviderInfo;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author lfy
 */
public class RedisDiscovery implements Discovery {
    public static void main(String[] args) {
        RedisDiscovery discovery = new RedisDiscovery("127.0.0.1",6379,"test_register");
        discovery.discovery(DiscoveryInfo.builder().serviceName("testService").build()
                , null, new Router() {
                    @Override
                    public List<ProviderInfo> route(List<ProviderInfo> urls, DiscoveryInfo providerInfo) {
                        System.out.println(urls);
                        return urls;
                    }
                }
        );
    }

    private JedisPool jedisPool;
    private String namespace;
    ScheduledExecutorService scheduledThreadPool;

    public RedisDiscovery(String host, int port, String namespace) {
        jedisPool = new JedisPool(host, port);
        this.namespace = namespace;
        scheduledThreadPool = Executors.newScheduledThreadPool(1);
    }

    @Override
    public List<ProviderInfo> discovery(DiscoveryInfo discoveryInfo, CustomInterceptor handler, Router router) {
        try {
            subscribe(handler, router, discoveryInfo);
            return discoveryProviderUrls(handler, router, discoveryInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public List<ProviderInfo> discovery(DiscoveryInfo discoveryInfo, Router router) {
        try {
            return discoveryProviderUrls(null, router, discoveryInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private List<ProviderInfo> discoveryProviderUrls(CustomInterceptor handler, Router router, DiscoveryInfo discoveryInfo) throws Exception {
        List<ProviderInfo> result = new ArrayList<>();
        String serviceName = discoveryInfo.getServiceName();
        String keyPrefix = namespace + ":" + serviceName + ":";
        try (Jedis jedis = jedisPool.getResource()) {
            Set<String> list = jedis.keys(keyPrefix + "*");

            for (String key : list) {
                findOne(result, key, jedis);
            }
            List<ProviderInfo> providers = router.route(result, discoveryInfo);
            if (providers == null || providers.size() == 0) {
                System.out.println("没有找到服务!");
            }
            if (handler != null) {
                handler.setProviders(providers);
            }
        }
        return result;
    }

    /**
     * 注册监听节点
     */
    public void subscribe(CustomInterceptor handler, Router router, DiscoveryInfo discoveryInfo) {
        try {
            scheduledThreadPool.scheduleAtFixedRate(() -> {
                //重新设置url
                try {
                    System.out.println("Discovery轮询注册中心中...");
                    discoveryProviderUrls(handler, router, discoveryInfo);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("Discovery轮询注册中心出现异常");
                }
            }, 0, 5, TimeUnit.SECONDS);


        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void findOne(List<ProviderInfo> result, String key, Jedis jedis) throws Exception {
        String read = jedis.get(key);
        ProviderInfo providerInfo = JSON.parseObject(read, ProviderInfo.class);
        result.add(providerInfo);
    }
}
